home *** CD-ROM | disk | FTP | other *** search
- ; ip.asm
- ;========================================================================
-
- ; Copyright (C) 1991 by Jan.Engvald@ldc.lu.se, see file COPYING.
-
- ;************************************************************************
- ;************************************************************************
- ;*
- ;* UDP/IP library
- ;*
- ;* This library is in a transition phase from a PDCLKSET specific library
- ;* into a multiprocess, reentrant, any hardware type, general UDP/IP
- ;* library. The buffers used have a descriptor part and a packet part.
- ;* The descriptor part is used to allow reentrancy, different physical
- ;* address lengths and varying number of IP options.
- ;*
- ;* In this library DS:BX always points to the descriptor buffer, DS:DI
- ;* usually points to the physical header/IP header/UDP header part of
- ;* the IP packet buffer and DX,AX often contains an IP number in network
- ;* byte order (DL,DH,AL,AH). For efficiency reasons, IP numbers are
- ;* searched last half first (first halves are often equal).
- ;*
- ;* As this library is still evolving, you can not assume that it looks
- ;* the same in the next release. In particular, if you are using any of
- ;* of the subroutines, check if their calls or results have been changed.
- ;*
- ;* The current implementation is RFC791 (IP) and RFC1122 (host requirements)
- ;* compliant, except for a few cases: I havn't found a reasonable solution
- ;* on how to report back to the application ICMP errors like parameter
- ;* problem, protocol and port unreachables, and fragment reassembly time
- ;* exceeded. Also, IP options are allowed, but the interpretation and handling
- ;* must be done by the application. Apart from the above, it is a de luxe
- ;* implementation that includes things like multiple default gateways,
- ;* sending protocol and port unreachables, IP type of service handling (not
- ;* tested), fragment reassembly and source quench introduced delay.
- ;*
- ;************************************************************************
- ;************************************************************************
-
- ; send errors:
- SERRUNREACH equ 0 ; host or net unreachable
- SERRNOBUF equ 2 ; temporary out of buffers
- SERRNOARP equ 4 ; got no ARP reply
- SERRTIMOUT equ 6 ; general timeout
- SERRNOTRAF equ 8 ; received no traffic from dst
-
- ICMP_PROT equ 1 ; Internet Control Msg Prot
- UDP_PROT equ 17 ; IP protocol type UDP
-
- Descriptor struc
- dLink LinkStruc <> ; next & prev links
- ; dIOCB iocb <> ; pkt drvr hi perf struc
- dPtrPhys dw 0 ; ptr to physical hdr
- dPtrIp dw 0 ; ptr to IP hdr
- dPtrUdp dw 0 ; ptr to UDP hdr
- dPktLen dw 0 ; packet length (bytes)
- dPktEnd dw 0 ; end of packet
- dTimOut2Msg equ dPktEnd ; Timeout msg for findsends
- dSqDelay dw 0 ; source quench delay (ms)
- dWaitEvent dw 0 ; event to wait for
- dPtrFrag equ dWaitEvent ; ptr to defargment listhead
- dTimOutMsg dw 0 ; to be displayed at timeout
- dTickResend dw 1*18 ; resend start interval (ticks)
- dTickTimeout dw 4*18 ; timeout ticks (in 1/18 s)
- dTick2Timeout dw 14*18 ; second timeout
- dIdxHwDst equ dSqDelay ; arp table index for hw dst
- dIdxIpDst equ dTick2Timeout ; arp table index for IP dst
- dAdjust equ (4-(($-dLink) and 3)) and 3
- if dAdjust
- db dAdjust dup (0)
- endif
- dGwys2Chk db 0 ; # of untried gateways
- dSnap db 0 ; 802.3 snaps used
- dPtrDes dw 0 ; ptr to start of descriptor
- dHwDst equ $-dLink ; (part of pd packet)
- DESCRLEN equ $-dLink
- Descriptor ends
-
- HwStruc struc
- hEthDst db 6 dup (0) ; Ethernet destination address
- hEthSrc db 6 dup (0) ; my Ether addr
- hProtType dw 0008 ; 0800 = IP
- HWHDRLEN equ $-hEthDst
- HwStruc ends
-
- SnapStruc struc
- sDSAP db 170
- sSSAP db 170
- sContr db 3
- sOrgCode db 0,0,0
- sProt db 08, 00
- SNAPLEN equ $-sDSAP
- SnapStruc ends
-
- IpStruc struc
- iIpVerHlen db 45h ; ver 4, 5 32-bit hdr words
- iIpTos db 0 ; type of service
- iIpLen dw 0 ; IP packet length
- iIpId dw 0100h ; id 0001
- iIpFlFrag dw 0 ; no flags or fragments
- iIpTtl db 90 ; time to live
- iIpProt db 0 ; 17 = udp
- iIpXsum dw 0 ; header checksum
- iIpSrc dw 0, 0 ; Don't know my IP nmbr
- iIpDst dw 0ffffh, 0ffffh ; local net broadcast IP
- iIpOptions equ $-iIpVerHlen
- IPHDRLEN equ $-iIpVerHlen
- IpStruc ends
-
- UdpStruc struc
- uUdpSrc dw 4400h ; source port 44h = 68
- uUdpDst dw 4300h ; dest port 43h = 67
- uUdpLen dw 0 ; length in bytes
- uUdpXsum dw 0 ; udp checksum
- uUdpData equ $-uUdpSrc
- UDPHDRLEN equ $-uUdpSrc
- UdpStruc ends
-
- BootpStruc struc
- uUdpStruc UdpStruc <>
- uBotOp db 1 ; bootp request
- uBotHtype db 0 ; hardware type
- uBotHlen db 0 ; hardware addr lenght
- uBotHops db 0 ; hops
- uBotXid dw 0, 0 ; transaction id
- uBotSecs dw 0001 ; 0100h seconds since boot
- uBotUnused dw 0 ; not defined
- uBotCliIp dw 0, 0 ; Client IP unknown
- uBotYourIp dw 0, 0 ; my IP yet unknown
- uBotServIp dw 0, 0 ; Server IP
- uBotGwyIp dw 0, 0 ; Gateway IP
- uBotCliHwAd db 16 dup (0) ; My Hardware address
- uBotSname db 64 dup (0) ; server name
- uBotFilNam db 128 dup (0) ; file name
- uBotMagNum dw 8263h, 6353h ; Magic number
- uBotVend db 64-4 dup (0) ; Vendor specific area
- BpDataLen = $-uBotOp
- BootpStruc ends
-
- IcmpStruc struc
- uIcmpTypecode dw 0
- uIcmpXsum dw 0
- uIcmpData dw 0, 0
- uIcmpIpHdr dw iIpOptions+4 dup (0)
- ICMPHDRLEN equ uIcmpIpHdr-uIcmpTypecode
- IcmpStruc ends
-
- BootpFrame struc
- fDescriptor Descriptor <>
- fHwStruc HwStruc <>
- fIpStruc IpStruc <>
- fBotStruc BootpStruc <>
- BpLen = $-fHwStruc
- BootpFrame ends
-
- even
- Events dw 1 ; =1 so DONT_WAIT always true
- DONT_WAIT equ 1
- GOT_BOOTP equ 2
- GOT_ARPREPLY equ 4
- GOT_TIMEREPLY equ 8
- GOT_ARPREQ equ 16
- GOT_ICMPMSG equ 32
- GOT_NSREPLY equ 64
-
- GenFlags dw 0
- ARGZONE equ 2
- ARGZONESPEC equ 4
- DSTNOW equ 8
- IS_386 equ 16
- TBL_READY equ 32
- DBGINTERR equ 08000h
-
- MySegm dw 0
- Hlen dw 0
- H2Len dw 0
- MyMask dw 2 dup (0h)
- MyNet dw 2 dup (0h)
- IpHandle dw 0
- IpIdCounter dw 0
- InSendAndW dw 0
-
- ifndef MAXDEFGWYS
- MAXDEFGWYS equ 4
- endif
-
- DefGwyIndex dw 0
- DefGwyNum dw 0
- DefGwys dw MAXDEFGWYS*2 dup (0)
-
- if TBLBUILD or PINGCLIENT
- DefNSnum dw 0
- DefNS dw MAXDEFNS*2 dup (0)
- endif ; TBLBUILD or PINGCLIENT
-
- ifndef ROUTESLOTS
- ROUTESLOTS equ 8
- endif
-
- ; The route table contains information on hosts behind gateways.
- ;
- ; If we don't receive anything from an IP number within one minute after we
- ; last sent to it, we return SERRNOTRAF on the next send. This is cleared
- ; after another minute.
-
- RouteTabIpD2 dw ROUTESLOTS dup (0) ; destination IP #
- RouteTabIpD1 dw ROUTESLOTS dup (0)
- RouteTabTos dw ROUTESLOTS dup (0) ; type of service
- RouteTabIpG2 dw ROUTESLOTS dup (0) ; gateway IP #
- RouteTabIpG1 dw ROUTESLOTS dup (0)
- RouteTabTrTx dw ROUTESLOTS dup (0) ; transmitt timer
- RouteTabTrRx dw ROUTESLOTS dup (0) ; receive timer
- RouteTabFlags dw ROUTESLOTS dup (0) ; flags (must follow TrRx)
- RouteTabTrSq dw ROUTESLOTS dup (0) ; source quench timer
- RouteTabSqDelay dw ROUTESLOTS dup (0) ; source quench delay
- RouteTabUnreach dw ROUTESLOTS dup (0) ; destination unreachable
-
- RoutePutSlot dw 0
-
- IpDesBuf BootpFrame <>
-
- SnapHdr SnapStruc <>
-
- IpHdr equ IpDesBuf.fIpStruc
- MyIpNr equ IpDesBuf.fIpStruc.iIpSrc
-
-
-
- ;************************************************************************
- ;* SendUdpFind
- ;*
- ;* Input: BX = IP description buffer ptr (BX saved)
- ;* DX = addr of length prepended IP list to send to until reply
- ;* Output: Zero and CX = 0 if OK
- ;* non-zero and CX = errorcode if error
- ;* Destroys: AX, CX, DX, SI, DI, ES and flags
- ;************************************************************************
-
- SendUdpFind proc near
- mov [bx].dTimoutMsg,0 ; continue even if no reply
- mov ah,2 ; do 2 turns over all IP #s
- Send2ndTurn:
- mov si,dx ; get IP list addr
- lodsb ; # of IP numbers to al
- inc si
- SendNextIP:
- mov di,[bx].dPtrIp
- lea di,[di].iIpDst
- movsw ; put next IP number
- movsw
-
- cmp ax,0101h ; last IP last turn?
- jne Send2orMore
- mov di,[bx].dTimOut2Msg
- mov [bx].dTimoutMsg,di ; -yes, terminate if no reply
- Send2orMore:
- push ax
- push dx
- push si
- mov ax,[bx].dPktLen
- call SendUdpPkt ; send udp packet
- pop si
- pop dx
- pop ax
- jz SendUdpFindRet ; done if reply
-
- dec al
- jnz SendNextIP ; more IP numbers this turn?
-
- mov di,[bx].dTick2Timeout ; -no, use longer timeout
- mov [bx].dTickTimeout,di ; for 2nd turn
- dec ah
- jnz Send2ndTurn ; both turns done?
-
- or cx,cx
- SendUdpFindRet:
- ret
- SendUdpFind endp
-
-
-
- ;************************************************************************
- ;* SendUdpPkt
- ;*
- ;* Input: AX = IP data byte length (AX destroyed)
- ;* BX = IP description buffer ptr (BX saved)
- ;* Output: Zero and CX = 0 if OK
- ;* non-zero and CX = errorcode if error
- ;* Destroys: AX, CX, DX, SI, DI, ES and flags
- ;************************************************************************
-
- SendUdpPkt proc near
- push ax
- xchg ah,al
- mov di,[bx].dPtrUdp
- mov [di].uUdpLen,ax ; fill in UDP total length
-
- mov [di].uUdpXsum,ax ; ensure chksum is calculated
-
- mov di,[bx].dPtrIp
- mov [di].iIpProt,UDP_PROT ; set UDP protocol
-
- call UdpChkSum ; calculate UDP checksum
-
- pop ax
- call SendIpPkt ; send UDP packet
-
- ret
- SendUdpPkt endp
-
-
-
- ;************************************************************************
- ;* SendIcmpPkt
- ;*
- ;* Input: BX = IP description buffer ptr (BX saved)
- ;* CX = IP data length
- ;* Output: Zero and CX = 0 if OK
- ;* non-zero and CX = errorcode if error
- ;* Destroys: AX, CX, DX, SI, DI, ES and flags
- ;************************************************************************
-
- SendIcmpPkt proc near
- push cx ; save length
-
- call IcmpChkSum ; calculate icmp checksum
-
- mov [bx].dWaitEvent,0 ; don't wait for answer
- mov di,[bx].dPtrIp
- mov [di].iIpProt,ICMP_PROT
-
- pop ax ; restore length
- ; call SendIpPkt
- ; ret
- SendIcmpPkt endp
-
-
-
- ;************************************************************************
- ;* SendIpPkt
- ;*
- ;* Input: AX = IP data byte length (AX destroyed)
- ;* BX = IP description buffer ptr (BX saved)
- ;* Output: Zero and CX = 0 if OK
- ;* non-zero and CX = errorcode if error
- ;* Destroys: AX, CX, DX, SI, DI, ES and flags
- ;************************************************************************
-
- SendIpPkt proc near
- call IPHdrLength ; calculate IP hdr length
-
- mov dx,MyIpNr ; my IP # to IP src
- mov [si].iIpSrc,dx
- mov dx,MyIpNr+2
- mov [si].iIpSrc+2,dx
-
- add ax,cx ; add hdr length to data length
- mov [bx].dPktLen,ax ; and save it
-
- xchg ah,al
- mov [si].iIpLen,ax ; fill in IP length
-
- mov dx,IpIdCounter
- mov [si].iIpId,dx ; unique id for frag reassembly
- inc dx
- mov IpIdCounter,dx
-
- call IpChkSum ; calculate checksum
- if RFCC
- call Ageing ; clear unused table slots
- endif ; RFCC
- call PutPhysDst ; do we have HW dest addr?
- jnz SendIpRet ; -no, ARP timed out
-
- call PutPhysSrc ; put my HW src addr
-
- add [bx].dPktLen,cx ; pkt length (HW addr part)
-
- jmp short SendAndWait ; -yes, send packet
- SendIpRet:
- ret
- SendIpPkt endp
-
-
-
- ;************************************************************************
- ;* SendAndWait
- ;* Input: BX = description buffer ptr (saved)
- ;* Output: Zero and CX = 0 if OK
- ;* non-zero and CX = errorcode if error
- ;* Destroys: AX, CX, DX, SI, DI, ES, flags
- ;************************************************************************
-
- SendAndWait proc near
- inc InSendAndW
- mov si,[bx].dWaitEvent ; event to wait for
-
- or si,si ; no event to wait for?
- jz SendDontWait
-
- not si
- and Events,si ; clear this event bit
- SendDontWait:
- not si
- if RFCC
- ; Do RFC1016 Source Quench Introduced Delay
-
- mov ax,[bx].dSqDelay ; SQ delay (ms)
- add ax,32 ; round up
- mov cl,6
- shr ax,cl ; convert ms to ticks
- call CurrentTicks
- add ax,cx ; time to send at
- SendSqLoop:
- call CurrentTicks
- cmp cx,ax ; can we send it now?
- jns SendNoSqDelay
- call Something2Do ; - no, wait a while
- jmp short SendSqLoop
- SendNoSqDelay:
- else
- call CurrentTicks
- endif ; RFCC
- call SendRawPkt ; send packet part of buffer
-
- mov di,[bx].dTickResend ; first resend time
- mov ax,cx
- add ax,di
-
- mov dx,cx
- add dx,[bx].dTickTimeout ; time out time
- WaitLoop:
- test Events,si ; got what we want?
- jz SendChk
- SendWaitOK:
- xor cx,cx
- SendWaitRet:
- dec InSendAndW
- or cx,cx
- ret
-
- SendChk:
- call Something2Do ; anything else to do?
- ChkTimeout:
- call CurrentTicks
- cmp cx,dx ; time out?
- jns SendTimedout
-
- cmp cx,ax ; time to resend?
- js WaitLoop
-
- shl di,1 ; double resend time
-
- cmp di,30*18
- jbe SendDouble
- mov di,30*18 ; max 30 seconds
- SendDouble:
- add ax,di ; next resend time
-
- call SendRawPkt ; send same packet again
- jmp short WaitLoop
- SendTimedout:
- mov dx,[bx].dTimOutMsg
- mov cx,SERRTIMOUT
- or dx,dx ; if no timeout msg
- jz SendWaitRet ; just return
-
- mov ah,9 ; print error msg in dx
- int 21h
- mov al,04 ; error code 4
- call Terminate
- SendAndWait endp
-
-
-
- ;************************************************************************
- ;* SendRawPkt
- ;* Input: BX = description buffer ptr (saved)
- ;* Destroys: flags
- ;*
- ;* (The saving of all registers below is not needed for the Crynwr
- ;* collection of packet drivers, but as far as I understand the packet
- ;* driver specification other drivers may need it.)
- ;************************************************************************
-
- SendRawPkt proc near
- push dx
- push cx
- push bx
- push ax
- push si
- push di
- push bp
- push es
-
- mov si,[bx].dPtrPhys ; get start of packet
- mov cx,[bx].dPktLen ; and its length
-
- mov ah,4 ; send packet to
- push ds ; packet driver
- int_pkt
- pop ds
-
- pop es
- pop bp
- pop di
- pop si
- pop ax
- pop bx
- pop cx
-
- jc BadPkt ; any errors?
-
- pop dx
- ret
- BadPkt:
- call print_error ; display explanation
-
- mov al,03 ; error code 3
- call Terminate
- SendRawPkt endp
-
-
-
- ;************************************************************************
- ;* PutPhysSrc
- ;*
- ;* Input: BX = IP description buffer ptr (saved)
- ;* Output: HW src addr and IP prot type put into pkt
- ;* CX = phys header length
- ;* Destroys: CX, SI, DI, ES, flags
- ;************************************************************************
-
- PutPhysSrc proc near
- mov si,offset MyHwAd ; get my HW addr from ARP buf
- mov di,[bx].dPtrPhys
- mov cx,Hlen
- add di,cx
- push cs
- pop es
- rep movsb ; put my HW addr as src HW addr
-
- test [bx].dSnap,1
- jz PutPhysNotSnap
-
- mov cx,[bx].dPktLen
- add cx,8
- xchg ch,cl
- mov [di],cx
- add di,2
-
- mov cx,sProt-sDSAP
- mov si,offset SnapHdr
- rep movsb
- PutPhysNotSnap:
- mov cx,di
- sub cx,[bx].dPtrPhys
- add cx,2 ; physical header length
-
- mov word ptr [di],0008h ; protocol type IP (0800)
-
- ret
- PutPhysSrc endp
-
-
-
- ;************************************************************************
- ;* PutPhysDst
- ;*
- ;* Input: BX = IP description buffer ptr (saved)
- ;* Output: Zero and CX = 0 if OK
- ;* non-zero and CX = errorcode if error
- ;* Destroys: AX, CX, DX, SI, DI, ES, flags
- ;************************************************************************
-
- PutPhysDst proc near
- mov ax,DefGwyNum ; # of default gwys we have
- mov [bx].dGwys2Chk,al ; gwys still left to check
- PutPhysAgain:
- mov di,[bx].dPtrIp
- mov al,[di].iIpTos ; get type of service
- xor ah,ah
- mov si,ax
-
- mov dx,[di].iIpDst ; set dx,ax = dst IP #
- mov ax,[di].iIpDst+2
-
- call ArpPutHwDst ; do we know dst phys addr?
- jz FoundArpEntry ; - yes, copied hw addr
-
- call MyNetChk ; - no. Is dst on my net?
- jz PutMynetArp ; - yes, don't use gwy
- ; and ARP dst
- call UseGwy ; - no, use a gateway
- jcxz PutArp ; destination unreachable?
- jmp short PutPhysRet
-
- PutMynetArp:
- mov [bx].dGwys2Chk,1
- PutArp:
- call ArpPutHwDst ; have hw addr for this IP # ?
- jz FoundArpEntry ; - yes, copied hw addr to pkt
-
- call SendArpReq ; - no, arp for it
- jz PutPhysAgain ; if reply, put in hw addr
-
- call SwitchGwy ; else try next gwy
-
- mov cx,SERRNOARP
- dec [bx].dGwys2Chk ; any more default gwys?
- jnz PutPhysAgain
-
- PutPhysRet:
- or cx,cx
- FoundArpEntry:
- ret
- PutPhysDst endp
-
-
-
- ;************************************************************************
- ;* RouteFind
- ;*
- ;* Input: DX = first word of dst IP # (saved if not found)
- ;* AX = second word of dst IP # (saved if not found)
- ;* SI = IP type of service
- ;* Output: if found: zero and DI = route table index
- ;* DX = first word of gwy IP #
- ;* AX = second word of gwy IP #
- ;* CX = net/host unreachable code
- ;* Destroys: CX, DI, ES, flags
- ;************************************************************************
-
- RouteFind proc near
- mov di,offset RouteTabIpD2
- mov cx,ROUTESLOTS
- or cx,cx ; ensure non-zero flag
- PushfDI
- RouteFindNext: ; look for matching slot
- repne scasw
- jnz RouteFindRet
-
- cmp dx,2*RouteSLOTS-2[di] ; does dst IP first part match?
- jne RouteFindNext ; - no, look further
-
- cmp si,4*RouteSLOTS-2[di] ; does dst tos match?
- jne RouteFindNext ; - no, look further
-
- sub di,offset RouteTabIpD2+2 ;- yes, compute slot index
-
- mov dx,RouteTabIpG1[di] ; get gwy IP #
- mov ax,RouteTabIpG2[di] ;
-
- mov cx,RouteTabUnreach[di] ; get unreachable code
-
- PopfEI
- cmp di,di ; set zero flag
- ret ; zero (found) return
-
- RouteFindRet:
- PopfEI
- ret ; non zero (not found) return
- RouteFind endp
-
-
-
- ;************************************************************************
- ;* MyNetChk
- ;*
- ;* Input: DX = first word of IP # (saved)
- ;* AX = second word of IP # (saved)
- ;* Output: zero if same net else non-zero
- ;* Destroys: flags
- ;************************************************************************
-
- MyNetChk proc near
- push ax
- push dx
-
- and dx,MyMask ; check if my net
- cmp dx,MyNet
- jne MyNetRet
- and ax,MyMask+2
- cmp ax,MyNet+2
- MyNetRet:
- pop dx
- pop ax
- ret
- MyNetChk endp
-
-
-
- ;************************************************************************
- ;* UseGwy
- ;*
- ;* Input: DX = first word of destination IP #
- ;* AX = second word of destination IP #
- ;* SI = IP type of service
- ;* Output: DX = first word of gateway IP #
- ;* AX = second part of gateway IP #
- ;* CX = net/host unreachable code
- ;* Destroys: CX, SI, DI, ES, flags
- ;************************************************************************
-
- UseGwy proc near
- PushfDI
-
- call RouteFind ; is dst in route tbl?
- jz short UseGwyKnown ; - yes, have gwy IP #
- ; - no, use default gwy
- dec cx
- cmp dl,127 ; don't send to 127.x.x.x
- je UseGwyRet
-
- mov di,RoutePutSlot
- add di,2 ; advance index two bytes
- cmp di,ROUTESLOTS*2 ; at end of table?
- jb UseRouteSlot
-
- xor di,di ; - yes, wrap around
- UseRouteSlot:
- mov RoutePutSlot,di
- mov RouteTabIpD1[di],dx ; put destination IP #
- mov RouteTabIpD2[di],ax
- mov RouteTabTos[di],si
-
- mov si,DefGwyIndex
- shl si,1
- shl si,1
- mov dx,DefGwys[si]
- mov ax,DefGwys+2[si]
- mov RouteTabIpG1[di],dx ; and default gwy IP #
- mov RouteTabIpG2[di],ax ; into route table
-
- call CurrentTicks
- mov RouteTabTrRx[di],cx ; put current time
-
- xor cx,cx ; initialize other fields
- mov RouteTabUnreach[di],cx ; clear unreachable
- mov RouteTabFlags[di],cx
- mov RouteTabSqDelay[di],cx
-
- or si,dx
- or si,ax ; any non-zero gwy IP #?
- jz UseGwyNone ; - yes
- UseGwyKnown:
- if RFCC
- push cx
- push ax
- call CurrentTicks
- mov RouteTabTrTx[di],cx ; transmit time
-
- mov ax,RouteTabSqDelay[di] ; move sq delay to descriptor
- mov [bx].dSqDelay,ax
- dec ax ; any delay?
- js UseNoSqDelay
- mov ax,RouteTabTrSq[di] ; - yes
- add ax,18 ; has one second passed
- cmp ax,cx ; since we last decremented
- jns UseNoSqDelay ; the delay value?
- mov RouteTabTrSq[di],cx
- dec RouteTabSqDelay[di] ; - yes, one millisecond off
- UseNoSqDelay:
- pop ax
- pop cx
- endif ; RFCC
- UsegwyRet:
- PopfEI
- ret
-
- UseGwyNone:
- PopfEI
- mov dx,offset NoGwyMsg
- mov ah,9 ; - no, print error msg in dx
- int 21h
- mov al,08 ; error code 8
- call Terminate
- UseGwy endp
-
-
-
- ;************************************************************************
- ;* SwitchGwy
- ;*
- ;* Input: DX = first word of gateway IP # (saved)
- ;* AX = second word of gateway IP # (saved)
- ;* Destroys: CX, DI, ES, flags
- ;************************************************************************
-
- SwitchGwy proc near
- PushfDI
- mov di,DefGwyIndex ; if current default gateway
- shl di,1
- shl di,1
-
- cmp dx,DefGwys[di] ; is the one
- jne SwitchNotThis
- cmp ax,DefGwys+2[di] ; that failed
- jne SwitchNotThis
-
- shr di,1
- shr di,1
- inc di ; then switch to
- cmp di,DefGwyNum
- jb SwitchNextGwy
- xor di,di
- SwitchNextGwy:
- mov DefGwyIndex,di ; next default gateway
- SwitchNotThis:
- PopfEI
-
- mov di,offset RouteTabIpG2 ; remove failing gateway
- mov cx,ROUTESLOTS ; from all route slots
- PushfDI
- SwitchRouteNext: ; look for matching slot
- repne scasw
- jnz SwitchGwyRet ; all entries searched
-
- cmp dx,2*ROUTESLOTS-2[di] ; does gwy IP 2nd part match?
- jne SwitchRouteNext ; - no, look further
-
- sub di,offset RouteTabIpG2+2 ;- yes, clear this route
- mov RouteTabIpD1[di],0
- mov RouteTabIpD2[di],0
- mov RouteTabIpG1[di],0
- mov RouteTabIpG2[di],0
- add di,offset RouteTabIpG2+2
- jmp short SwitchRouteNext ; more routes using this gwy?
-
- SwitchGwyRet:
- PopfEI
- ret
- SwitchGwy endp
-
-
-
- ;************************************************************************
- ;* ChkSum
- ;* Input: SI = start addr
- ;* CX = # of bytes
- ;* Output: AX = 1-complement checksum
- ;* CX = partial checksum
- ;* SI = addr of next byte
- ;* Destroys: Flags
- ;************************************************************************
-
- ChkSum proc near
- if PINGCLIENT
- test GenFlags,IS_386
- jz ChkSum8086
-
- .386
- push edx ; save 386 registers
- push eax
- shr cx,1 ; divide by two, round down
- pushf ; keep odd bit in carry
- shr cx,1
- pushf
- xor edx,edx ; clear edx and carry
- ChkLoop386:
- lodsd
- adc edx,eax ; add to previous running sum
- loopw ChkLoop386
-
- adc edx,0 ; add the last carry in again
- mov eax,edx
- shr eax,16
- add dx,ax
- adc dx,0
-
- popf ; odd # of words?
- jnc NotOddWords
-
- lodsw
- add dx,ax
- adc dx,0
- NotOddWords:
- popf ; odd # of bytes?
- jnc NotOddBytes
-
- lodsb ; get that last byte
- xor ah,ah ; clear carry and the high portion
- add dx,ax ; add the last one in
- adc dx,0 ; add the carry in, too
- NotOddBytes:
- pop eax
- mov ax,dx
- mov cx,dx
- pop edx
-
- not ax ; take one more 1-complement
- ret
-
- .8086
- endif ; PINGCLIENT
-
- ChkSum8086:
- push dx
- shr cx,1 ; divide by two, round down
- pushf ; keep odd bit in carry
- xor dx,dx ; clear dx and carry
- ChkLoop:
- lodsw
- adc dx,ax ; add to previous running sum
- loop ChkLoop
-
- adc dx,0 ; add the last carry in again
-
- popf ; odd # of bytes?
- jnc NotOdd
-
- lodsb ; get that last byte
- xor ah,ah ; clear carry and the high portion
- add dx,ax ; add the last one in
- adc dx,0 ; add the carry in, too
- NotOdd:
- mov ax,dx
- mov cx,dx
- pop dx
-
- not ax ; take one more 1-complement
- ret
- ChkSum endp
-
-
-
- ;************************************************************************
- ;* UdpChkSum (both for generate and check!)
- ;*
- ;* Input: BX = IP description buffer ptr (saved)
- ;* Output: Zero if OK; checksum filled in
- ;* SI = addr of next byte
- ;* DI = IP Ptr
- ;* Destroys: AX, CX, DX, SI, DI, flags
- ;************************************************************************
-
- UdpChkSum proc near
- mov si,[bx].dPtrIp
- mov di,[bx].dPtrUdp
-
- xor cx,cx ; save ttl for pseudo hdr
- xchg cl,[si].iIpTtl ; usage
- push cx
-
- xor dx,dx
- xchg dx,[di].uUdpXsum ; save and clear checksum
-
- mov cx,[di].uUdpLen ; save UDP length
- mov [si].iIpXsum,cx
- xchg ch,cl
-
- mov ax,di
- add ax,cx
- or dx,dx ; is there a checksum?
- mov si,ax ; - no, not available/wanted
- jz UdpNoSum ; but set si to end of data
-
- push cx ; - yes
- mov cx,12 ; checksum pseudo hdr
- mov si,[bx].dPtrIp
- add si,iIpTtl
- call ChkSum
-
- mov [di].uUdpXsum,cx ; move partial checksum
- ; into udp hdr
- pop cx ; checksum udp hdr+data
- mov si,di
- call ChkSum
- jnz UdpNotZero ; checksum is zero?
- not ax ; - yes, make it FFFFh
- UdpNotZero:
- mov [di].uUdpXsum,ax
-
- cmp ax,dx ; does checksums match?
- UdpNoSum:
- pop cx
- mov di,[bx].dPtrIp
- mov [di].iIpTtl,cl ; restore ttl
-
- ret
- UdpChkSum endp
-
-
-
- ;************************************************************************
- ;* IpHdrLength
- ;*
- ;* Input: BX = IP description buffer ptr (saved)
- ;* Output: CX = IP header byte length
- ;* SI = pointer to IP header
- ;* Destroys: SI, flags
- ;************************************************************************
-
- IpHdrLength proc near
- mov si,[bx].dPtrIp
- mov cx,[si] ; get version+length byte
- and cx,0fh ; length (32 bit words)
- shl cx,1 ; convert to
- shl cx,1 ; byte length
- ret
- IpHdrLength endp
-
-
-
- ;************************************************************************
- ;* IpChkSum (both for generate and check!)
- ;*
- ;* Input: BX = IP description buffer ptr (saved)
- ;* Output: Zero if OK; checksum filled in
- ;* Destroys: AX, CX, DX, SI, DI, flags
- ;************************************************************************
-
- IpChkSum proc near
- xor dx,dx
- mov di,[bx].dPtrIp
- xchg dx,[di].iIpXsum ; save and clear checksum
-
- call IpHdrLength
- call ChkSum ; calculate new checksum
- mov [di].iIpXsum,ax
-
- cmp ax,dx ; does checksums match?
- ret
- IpChkSum endp
-
-
-
- ;************************************************************************
- ;* IcmpChkSum (both for generate and check!)
- ;*
- ;* Input: BX = IP description buffer ptr (saved)
- ;* CX = IP data length
- ;* Output: Zero if OK; checksum filled in
- ;* Destroys: AX, CX, DX, SI, DI, flags
- ;************************************************************************
-
- IcmpChkSum proc near
- xor dx,dx
- mov di,[bx].dPtrUdp
- xchg dx,[di].uIcmpXsum ; save and clear checksum
-
- mov si,di
- call ChkSum ; calculate new checksum
- mov [di].uIcmpXsum,ax
-
- cmp ax,dx ; does checksums match?
- ret
- IcmpChkSum endp
-
-
-
- ;************************************************************************
- ;* CurrentTicks
- ;* Output: CX = low word of ticks (1/18 second) counter
- ;* Destroys: CX, ES
- ;************************************************************************
-
- CurrentTicks proc near
- mov cx,040h ; DOS data segment
- mov es,cx
- mov cx,es:6ch ; get low word of ticks cntr
- push cs
- pop es
- ret
- CurrentTicks endp
-
-
- if RFCC
- ;************************************************************************
- ;* Ageing of ARP and Route tables
- ;*
- ;* Destroys: AX, CX, DX, SI, DI, ES, flags
- ;************************************************************************
-
- AgeNext dw 0 ; time to check slots
-
- Ageing proc near
- PushfDI
- call CurrentTicks ; get current ticks value
- cmp cx,AgeNext
- jns AgeNow ; time to do ageing?
-
- PopfEI
- ret
-
- AgeNow:
- mov di,cx
- mov dx,cx
- add cx,2*18 ; chk next 2 seconds from now
- mov AgeNext,cx
-
- sub dx,65*18 ; clear what is older than 1 min
-
- mov cx,ARPSLOTS-3
- mov si,offset ArpTabTr+6
- AgeArpLoop:
- and word ptr [si+2*ARPSLOTS],not SQ_UPDATED ; clr every 2 s
-
- lodsw
- cmp ax,dx
- jns AgeArpYoung ; not touched in a minute?
-
- sub si,offset ArpTabTr+2
- push cx
- push di
- push dx
- mov dx,ArpTabIp1[si]
- mov ax,ArpTabIp2[si]
- call switchGwy ; in case it's a gwy: switch
- pop dx
- pop di
- pop cx
-
- xor ax,ax
- mov ArpTabTr[si],di ; set current time
- mov ArpTabIp1[si],ax ; clear old entries
- mov ArpTabIp2[si],ax
- mov ArpTabHw1[si],ax
- mov ArpTabHw2[si],ax
- mov ArpTabHw3[si],ax
- add si,offset ArpTabTr+2
- AgeArpYoung:
- loop AgeArpLoop
- PopfEI
-
- mov cx,ROUTESLOTS
- mov si,offset RouteTabTrRx
- PushfDI
- AgeRouteLoop:
- and word ptr [si+2*ROUTESLOTS],not SQ_UPDATED ; clr every 2 s
-
- lodsw
- cmp ax,dx ; old slot?
- jns AgeRouteYoung
-
- sub si,offset RouteTabTrRx+2
- mov RouteTabTrRx[si],di
- xor ax,ax
- cmp RouteTabUnreach[si],ax ; any error code?
- jne AgeRouteUnr
-
- cmp dx,RouteTabTrTx[si] ; - no. Sent anything lately?
- jns AgeRouteEnd ; - no, that's why
-
- mov RouteTabUnreach[si],SERRNOTRAF ;- yes, somebody is dead
- jmp short AgeRouteEnd
- AgeRouteUnr: ; - yes, remove slot
- mov RouteTabIpD1[si],ax
- mov RouteTabIpD2[si],ax
- mov RouteTabIpG1[si],ax
- mov RouteTabIpG2[si],ax
- AgeRouteEnd:
- add si,offset RouteTabTrRx+2
- AgeRouteYoung:
- loop AgeRouteLoop
-
- PopfEI
- call AgeFrags ; release old fragments
-
- ret
- Ageing endp
-
-
-
- ;************************************************************************
- ;* VerifyIpHdr (RFC1122 requirements)
- ;*
- ;* verify IP dst = me (or bcast), process IP options, verify IPver=4,
- ;* verify IP src not bcast, set timer value in ArpTab and RouteTab.
- ;* Process IP fragments.
- ;************************************************************************
-
- holeStruc struc
- holeNext dw 0
- holeFirst dw 0
- holeLast dw 0
- HOLEDESCRLEN equ $-holeNext
- holeStruc ends
-
- k18 db 18
-
- VerifyIpHdr proc near
- push si
- push di
- mov al,[di].iIpVerHlen
- and al,0f0h
- cmp al,040h ; IP version 4?
- jne VerifyErr1
-
- mov di,[bx].dPtrPhys
- mov si,[di]
- mov dx,[di+2]
- mov ax,[di+4]
- call ArpFindHw ; find Hw Dst arp index
- mov [bx].dIdxHwDst,di ; 0 = bcast, 4 = me
-
- cmp MyIpNr,0
- je VerifyMeNotInArp
-
- cmp di,ARPMYIDX ; is Hw addr to me or bcats?
- ja VerifyErr1
- VerifyMeNotInArp:
- mov di,[bx].dPtrPhys
- add di,Hlen ; get physical src addr
- mov si,[di]
- mov dx,[di+2]
- mov ax,[di+4]
- call ArpFindHw ; is Hw Src in arp table?
- jz VerifyChkBcast ; - yes
-
- cmp [bx].dIdxHwDst,ARPMYIDX ; - no. Addressed to me?
- jne VerifyIpDst ;
-
- pop di ; - yes
- push di
- mov dx,[di].iIpSrc
- mov ax,[di].iIpSrc+2
-
- call MyNetChk ; if he is on my net
- jnz VerifyIpDst
-
- mov si,[bx].dPtrPhys
- add si,Hlen
- call ArpPutNew ; add him to arp table
- jmp short VerifyIpDst
-
- VerifyErr1: jmp short VerifyErr
-
- VerifyChkBcast:
- cmp di,ARPMYIDX ; from me or broadcast?
- jbe VerifyErr ; - yes, ignore packet
-
- call CurrentTicks ; get current ticks value
- mov ArpTabTr[di],cx
- VerifyIpDst:
- cmp MyIpNr,0
- je VerifyIpUnknown
-
- pop di
- push di
- mov dx,[di].iIpDst ; check IP dst
- mov ax,[di].iIpDst+2
- call ArpFindIp
- mov [bx].dIdxIpDst,di
- cmp di,ARPMYIDX ; is it to me or broadcast?
- ja VerifyErr ; - no, ignore packet
- VerifyIpUnknown:
- pop di
- push di
- mov dx,[di].iIpSrc
- mov ax,[di].iIpSrc+2
- call ArpFindIp
- jnz VerifyNoArp
-
- cmp di,ARPMYIDX ; from IP broadcast?
- jb VerifyErr ; -yes, ignore packet
- VerifyOK:
- call AgeFrags ; release old reassembly bufs
-
- pop di
- push di
- test [di].iIpFlFrag,0ff3fh ; is this a fragment?
- jnz VerifyFrag
- clc ; - no, use as is
- VerifyRet:
- pop di
- pop si
- ret
-
- VerifyNoArp:
- pop di
- push di
- mov cl,[di].iIpTos
- xor ch,ch
- mov si,cx
- call RouteFind ; is he in route table?
- jnz VerifyNoRoute
-
- call CurrentTicks
- mov RouteTabTrRx[di],cx ; note we've got pkts from him
- VerifyNoRoute:
- jmp short VerifyOK
-
- FragAddAndErr:
- mov si,offset FragList
- call AddToList
- VerifyFragErr:
- mov bx,bp
- VerifyErr:
- call BufRelease
- VerifyKeep:
- stc
- jmp short VerifyRet
-
- VerifyFrag: ; RFC 815 fragment reassembly:
- mov bp,bx ; addr of fragment buffer
- mov dx,[di].iIpSrc ; get IP # / IP id / IP prot
- mov ax,[di].iIpSrc+2
- mov si,[di].iIpId
- mov cx,Fraglist.lBufsAvail
- mov ch,[di].iIpProt
- FragLook4Buf:
- mov di,offset FragList
- call GetFromList
- jz FragEarliest ; any reassembly buffers?
-
- mov di,[bx].dPtrIp ; match IP#/Id/Prot
- cmp dx,[di].iIpSrc
- jne FragNextBuf
- cmp ax,[di].iIpSrc+2
- jne FragNextBuf
- cmp si,[di].iIpId
- jne FragNextBuf
- cmp ch,[di].iIpProt
- je FragBufFound
- FragNextBuf:
- push si ; irrelevant buf, put it back
- mov si,offset FragList
- call AddToList
- pop si
- dec cl
- jnz FragLook4Buf
- FragEarliest:
- call FragFirstLast ; compute addr of fragment
- or ax,ax ; first part earliest?
- jnz FragOffset
-
- mov bx,bp
- mov di,[bx].dPtrUdp
- add di,dx
- cmp [bp].dHomeList,offset FreeBufs ; and a big buffer?
- je FragFirstHole ; - yes, no extra buffer needed
- FragOffset:
- call BufAlloc ; - no, create empty buffer
- jz VerifyFragErr
-
- add di,2+2*EADDR_LEN
- mov [bx].dPtrIp,di
-
- mov si,[bp].dPtrIP
- mov cx,[bp].dPtrUdp ; copy IP header
- sub cx,si
- call movemem
- mov [bx].dPtrUdp,di
- FragFirstHole:
- mov [di].holeNext,0 ; create first hole descriptor
- mov [di].holeFirst,0
- mov [di].holeLast,GIANT
- mov [bx].dPtrFrag,di
-
- add di,HOLEDESCRLEN ; mark end of info
- mov [bx].dPktEnd,di
- FragBufFound:
- call FragFirstLast ; compute addr of fragment
- lea di,[bx].dPtrFrag
- FragNextHole: ; 1. select next hole descr
- mov si,di
- mov di,[si].holeNext
- or di,di ; any more descriptors?
- jz FragEndHoles
-
- cmp ax,[di].holeLast ; 2. frag.first > hole.last?
- jae FragNextHole
-
- cmp dx,[di].holeFirst ; 3. frag.last < hole.first?
- jbe FragNextHole
-
- mov cx,[di].holeNext ; 4. delete current hole descr
- mov [si].holeNext,cx
-
- mov cx,[di].holeLast
- cmp ax,[di].holeFirst ; 5. frag.first > hole.first?
- jbe FragNoNew1
- mov [si].holeNext,di ; create new hole descr
- mov [di].holeLast,ax
- FragNoNew1:
- mov si,[bp].dPtrIp ; 6. if frag.more
- test [si].iIpFlFrag,0020h
- jz FragLastFrag
-
- cmp dx,cx ; and frag.last < hole.last?
- jae FragNextHole
-
- mov si,[bx].dPtrUdp
- add si,dx
- mov [si].holeFirst,dx ; create new hole descr
- mov [si].holeLast,cx
- mov cx,[bx].dPtrFrag
- mov [si].holeNext,cx
- mov [bx].dPtrFrag,si
-
- add si,HOLEDESCRLEN
- cmp si,[bx].dPktEnd
- jbe FragNextHole
- FragPktEnd:
- mov [bx].dPktEnd,si
- jmp short FragNextHole
-
- FragLastFrag: ; when last frag
- mov si,[bx].dPtrUdp ; prepare IP length
- add si,dx
- jmp short FragPktEnd
-
- FragEndHoles: ; 8. copy data to assembly buf
- cmp bx,bp ; do we need to copy?
- je FragTimeUpd
-
- or ax,ax ; if first frag
- jnz FragNotFirst
-
- mov si,[bx].dPtrUdp ; retain this IP header
- mov di,[bp].dPtrUdp ; and copy assembled data
- mov cx,[bx].dPktEnd ; to frag buffer
- sub cx,si
- add si,dx ; skip over first fragment
- add di,dx
- sub cx,dx
- call movemem
- mov [bp].dPktEnd,di
-
- mov cx,[bx].dPtrFrag
- mov [bp].dPtrFrag,cx
-
- xchg bx,bp ; and switch buffers
-
- mov cx,di
- sub cx,si ; hole ptr adjustment
- lea di,[bx].dPtrFrag
- FragUpdLoop:
- mov si,di
- mov di,[si].holeNext
- or di,di
- jz FragRelBuf ; end of hole list
-
- add di,cx
- mov [si].holeNext,di ; new pointer address
- jmp short FragUpdLoop
-
- FragNotFirst:
- mov si,[bp].dPtrUdp ; copy this frag to asm buf
- mov cx,dx
- sub cx,ax
- mov di,[bx].dPtrUdp
- add di,ax
- call movemem
- FragRelBuf:
- push bx ; release frag buf
- mov bx,bp
- call BufRelease
- pop bx
- FragTimeUpd:
- call CurrentTicks ; update timer entry
- mov di,[bx].dPtrIp
- mov al,[di].iIpTtl
- mul k18
- add cx,ax
- mov [bx].dTickTimeout,cx
-
- mov di,[bx].dPtrIp
- mov si,[bx].dPtrUdp
- cmp [bx].dPtrFrag,0 ; any holes?
- jne FragKeep ; - yes, wait for more pkts
-
- mov cx,[bx].dPktEnd ; - no
- mov ax,cx ; compute IP length
- sub cx,[bx].dPtrIp
- xchg ch,cl
- mov [di].iIpLen,cx
- sub ax,[bx].dPtrPhys
- mov [bx].dPktLen,ax ; and packet length
-
- add sp,4 ; pop si and pop di
- ret
-
- FragKeep:
- mov si,offset FragList ; keep buf a while
- call AddToList
- jmp VerifyKeep
- VerifyIpHdr endp
-
-
-
- ;************************************************************************
- ;* FragFirstLast
- ;************************************************************************
-
- FragFirstLast proc near
- mov di,[bp].dPtrIp ; compute frag.first
- mov ax,[di].iIpFlFrag
- xchg ah,al
- and ax,1fffh
- shl ax,1
- shl ax,1
- shl ax,1
- mov dx,[di].iIpLen ; compute frag.last (+1)
- xchg dh,dl
- add dx,[bp].dPtrIp
- sub dx,[bp].dPtrUdp
- add dx,ax
- cmp dx,GIANT-IPHDRLEN-HWHDRLEN ; fits in buffer?
- ja FragTooBig
-
- ret
-
- FragTooBig:
- add sp,2 ; remove return addr from stack
- jmp FragAddAndErr
- FragFirstLast endp
-
-
-
- ;************************************************************************
- ;* AgeFrags
- ;************************************************************************
-
- AgeFragsNext dw 0
-
- AgeFrags proc near
- call CurrentTicks
- cmp cx,AgeFragsNext
- jns AgeFragsNow ; time to age yet?
-
- ret
-
- AgeFragsNow:
- mov dx,cx
- add cx,2*18 ; check next in 2 seconds
- mov AgeFragsNext,cx
-
- push bx
- PushfDI
- mov cx,Fraglist.lBufsAvail
- AgeLook4Buf:
- mov di,offset FragList
- call GetFromList
- jz AgeNoMoreFrags ; any reassembly buffers?
-
- mov si,offset FragList
- cmp dx,[bx].dTickTimeout
- js AgenextBuf ; too old?
- ; - no, put it back
- mov si,[bx].dHomeList ; - yes, release it
- AgeNextBuf:
- call AddToList
-
- dec cl
- jnz AgeLook4Buf ; any more reassembly bufs?
- AgeNoMoreFrags:
- PopfEI
- pop bx
- ret
- AgeFrags endp
-
- endif ; RFCC
-
- ;************************************************************************
- ;* SwitchIpDst
- ;************************************************************************
-
- SwitchIpDst proc near
- mov si,[bx].dPtrIp
- SwitchIpDstB:
- mov dx,[si].iIpSrc ; mov his IP # to IP dst
- mov di,[bx].dPtrIp
- mov [di].iIpDst,dx
- mov dx,[si].iIpSrc+2
- mov [di].iIpDst+2,dx
- ret
- SwitchIpDst endp
-
-
-
- ;************************************************************************
- ;* InitIp
- ;************************************************************************
-
- InitIp proc near
- pushf
- pop ax
- or ax,7000h ;the 386 lets us set these bits
- push ax
- popf
- pushf
- pop ax
- test ax,7000h ;did the bits get set?
- jz IsNot386 ;no.
- or GenFlags,IS_386 ;yes, use a 386-optimized code
- IsNot386:
- push ds
- mov IpDesBuf.dPtrPhys,offset IpDesBuf.fHwStruc ; *test*
- mov IpDesBuf.dPtrIp,offset IpDesBuf.fIpStruc
- mov IpDesBuf.dPtrUdp,offset IpDesBuf.fBotStruc
-
- mov ax,1ffh ;driver_info
- int_pkt
- pop ds
- call fatal_error
-
- mov ah,2 ;access all packets.
- mov al,ch ;their class from driver_info().
- mov bx,dx ;their type from driver_info().
- mov dl,cl ;their number from driver_info().
- mov cx,2 ;type length of two.
- mov si,offset IpDesBuf.fHwStruc.hProtType
- push cs ;es:di -> our receiver.
- pop es
- mov di,offset IpRecv
-
- push ds
- int_pkt
- pop ds
-
- call fatal_error
-
- mov IpHandle,ax
-
- ret
- InitIp endp
-
-
-
- ;************************************************************************
- ;* EndProtocol
- ;************************************************************************
-
- EndProtocol proc near
- mov ah,3 ; release handle in bx
-
- push ds
- int_pkt
- pop ds
-
- call print_error
-
- ret
- EndProtocol endp
-
-
-
- ;************************************************************************
- ;* Terminate
- ;************************************************************************
-
- Terminate proc near
- pop bx ; remove return addr fr stack
- push ax
-
- cld
- push cs
- push cs
- pop ds
- pop es
- sti
-
- mov bx,IpHandle ; release ARP and IP handles
- call EndProtocol
- mov bx,ArpHandle
- call EndProtocol
- if PINGCLIENT
- cmp EchoTarget,0
- jz TermNoPing
- call RestoreTimer
- TermNoPing:
- endif ; PINGCLIENT
- pop ax
- push ax
- or al,al ; any errors?
- jz termnorm
-
- cmp EnoughWord,HAVE_MYIPNR ; clock errors?
- je termnorm
-
- mov dx,offset MsgNotSet ; display "clock not set"
- mov ah,9
- int 21h
- termnorm:
- pop ax
- push ax
- add al,'0'
- mov MsgTermNr,al ; show error # in end line
-
- mov si,offset MyHwAd
- mov di,offset MsgTermHw
- call PutHwNum ; put my HW addr
-
- mov si,offset MyIpNr
- mov di,offset MsgMyIp
- call PutIpNum ; put my IP #
-
- mov dx,offset MsgTerm ; End of PDCLKSET msg
- mov ah,9
- int 21h
-
- pop ax ; error code
- mov ah,4ch
- int 21h ; terminate program
- Terminate endp
-
-
-
-
- ;************************************************************************
- ;* IP receiver *
- ;************************************************************************
-
- IpRecv:
- pushf
- push ds ; set segment registers
- mov dx,cs
- mov ds,dx
- mov es,dx
- cld
-
- or ax,ax ; first or second call?
- jne IpRecv_1 ; - second, we've got data
- ; - first, they want a buf
- cmp cx,GIANT ; packet too long?
- ja IpRecTooBig
- if PINGCLIENT
- cmp cx,BUFBODYSML
- ja IpRecBig
-
- call BufAlSml
- jz IpRecBig
- pop ds
- popf
- retf
-
- IpRecBig:
- endif ; PINGCLIENT
- call BufAlloc ; get a receive buffer
- jz IpRecNoBuf
- IpRecRet0:
- pop ds
- popf
- retf
-
- if DEBUG
- DbgIpRecv:
- or GenFlags,DBGINTERR
- endif ; DEBUG
- IpRecNoBuf:
- if PINGCLIENT
- inc EchoDrop
- endif ; PINGCLIENT
- IpRecTooBig:
- xor di,di ; no buffer available
- mov es,di
- jmp short IpRecRet0
-
-
- IpRecv_1:
-
- ; If I understand PC interrupt handling correctly, the following stackswitch
- ; and interrupt enabling should not kill multiprocess reentrancy.
-
- cli ; switch to our
- mov word ptr SaveSP,sp ; interrupt stack
- mov word ptr SaveSS,ss
- mov sp,offset StackEnd
- mov ss,MySegm
- sti ; allow interrupts
- if DEBUG
- dec DbgIntCnt ; double interrupt?
- jnz DbgIpRecv
- endif ; DEBUG
- call BuildRecDescr ; calculate pointers etc
-
- call IpChkSum ; only accept a correct
- jne IpRecRet ; IP checksum
-
- mov [bx].dPtrUdp,si
- if RFCC
- call VerifyIpHdr ; verify and process IP hdr
- jc IpRecKeepBuf
- endif ; RFCC
- cmp [di].iIpProt,ICMP_PROT ; ICMP protocol?
- jne IpNotIcmp
- jmp IpRecIcmp
- IpNotIcmp:
- cmp [di].iIpProt,UDP_PROT ; UDP protocol?
- jne IpProtUnr
-
- call UdpChkSum ; if available, test
- jne IpRecRet ; UDP checksum
-
- cmp si,[bx].dPktEnd ; still within packet limit?
- jbe IpRecUdp
- IpRecRet:
- call BufRelease ; release receive buffer
- IPRecKeepBuf:
- if DEBUG
- inc DbgIntCnt
- endif ; DEBUG
- cli ; restore previous stack
- mov sp, word ptr SaveSP
- mov ss, word ptr SaveSS
- pop ds
- popf
- retf
-
-
- IpPortUnr:
- mov ah,3 ; port unreachable
- jmp short IpUnr
- IpProtUnr:
- mov ah,2 ; protocol unreachable
- IpUnr:
- if RFCC
- mov al,3 ; destination unreachable
-
- cmp [bx].dIdxHwDst,ARPMYIDX ; was it specifically to me?
- jne IpRecRet
-
- mov bp,bx
- call BufAlloc
- jz UnrEnd
- call MakeSendDescr
- mov si,[bp].dPtrIp ; copy IP header
- mov cx,[bp].dPtrUdp
- add cx,8 ; + 8 bytes
- sub cx,si
-
- call SwitchIpDstB ; return to sender
-
- mov di,[bx].dPtrUdp
- mov [di].uIcmpTypecode,ax ; set type and code
-
- add di,8
- call movemem
-
- sub di,[bx].dPtrUdp
- mov [bx].dPktLen,di ; set IP data length
-
- mov si,offset IcmpToDo ; put buf on the ICMP send list
- call AddToList
- UnrEnd:
- mov bx,bp
- endif ; RFCC
- jmp IpRecRet
-
-
- IpRecUdp:
- mov [bx].dPktEnd,si ; end of logical pkt
-
- mov di,[bx].dPtrUdp
- cmp word ptr [di].uUdpSrc,2500h ; Src port 0025 = 37 ?
- je IpRecvTime ; - must be time reply
- if TBLBUILD or PINGCLIENT
- cmp word ptr [di].uUdpSrc,3500h ; Name server (53)?
- jne $+5
- jmp IpRecvName
- endif ; TBLBUILD or PINGCLIENT
- cmp word ptr [di].uUdpSrc,4300h ; Src port 0043 = 67
- jne IpPortUnr
-
- cmp word ptr [di].uUdpDst,4400h ; Dst port 0044 = 68
- jne IpPortUnr
-
- cmp byte ptr [di].uBotOp,2 ; bootp reply?
- jne IpRecRet
- IpRecBootp:
- push di ; - must be bootp reply
- lea si,[di].uBotCliHwAd
- mov di,offset MyHwAd
- mov cx,Hlen
- repe cmpsb ; our Ethernet addr?
- pop di
- jne IpRecRet2
-
- mov ax,word ptr IpDesBuf.fBotStruc.uBotXid
- cmp ax,word ptr [di].uBotXid ; our random id?
- jne IpRecRet2
- mov ax,word ptr IpDesBuf.fBotStruc.uBotXid+2
- cmp ax,word ptr [di].uBotXid+2
- jne IpRecRet2
- ; yes, it's about me!
- mov dx,[di].uBotGwyIp ; saves an ARP request
- mov ax,[di].uBotGwyIp+2 ; in many cases
- mov si,[bx].dPtrPhys
- add si,Hlen
- call ArpPutNew
-
- test Events,GOT_BOOTP ; if first answer
- jnz IpRecRet2 ; save bootp answer
-
- mov AdrBootpReply,bx ; for further study
- or Events,GOT_BOOTP
- jmp IpRecKeepBuf
-
- IpRecvTime:
- test Events,GOT_TIMEREPLY ; already got reply?
- jnz IpRecRet2
-
- mov ax,[di].uUdpData ; save seconds
- mov cTime,ax ; since year 1900
- mov ax,[di].uUdpData+2
- mov cTime+2,ax
-
- mov di,[bx].dPtrIp ; save who was answering
- mov dx,[di].iIpSrc
- mov ax,[di].iIpSrc+2
- mov RespondingIpNr,dx
- mov RespondingIpNr+2,ax
- or Events,GOT_TIMEREPLY
- IpRecRet2:
- jmp IpRecRet
-
- if TBLBUILD or PINGCLIENT
- IpRecvName:
- mov si,offset NameToDo ; process nameserver reply
- call AddToList
- jmp IpRecKeepBuf
- endif ; TBLBUILD or PINGCLIENT
-
-
- IpRecIcmp:
- mov cx,[di].iIpLen ; calculate IP data length
- xchg ch,cl
- add cx,di
- sub cx,si
- mov [bx].dPktLen,cx ; save IP data length
-
- call SwitchIpDst ; in case we want to return it
-
- call IcmpChkSum ; valid ICMP checksum?
- jne IpRecRet2
-
- mov si,[bx].dPtrUdp ; point to ICMP header
- mov cx,[si].uIcmpTypecode ; get type and code
- mov dx,[si].uIcmpIpHdr.iIpDst ; get original IP hdr
- mov ax,[si].uIcmpIpHdr.iIpDst+2 ; dst IP #
-
- if PINGCLIENT
- cmp cl,0 ; echo reply?
- jne IpNotEchoReply
- call EchoCalc
- jmp IpRecRet
- endif ; PINGCLIENT
-
- if RFCC
- IpNotEchoReply:
- cmp cl,8 ; echo request?
- jne IpNotEchoReq
-
- cmp [bx].dIdxHwDst,ARPMYIDX ; broadcast?
- jb IpRecRet2 ; - yes, don't echo
-
- mov byte ptr [si].uIcmpTypecode,0 ; put echo reply value
-
- mov si,offset IcmpToDo ; put buf on the ICMP send list
- call AddToList
- jmp IpRecKeepBuf
-
- IpNotEchoReq:
- endif ; RFCC
-
- cmp cx,11 ; TTL exceeded?
- je IpIcmpUnreach
-
- cmp cl,3 ; unreachable
- jne IpNotUnreach
-
- cmp ch,12 ; net or host unreachable?
- ja IpIcmpRet2
- cmp ch,6
- ja IpIcmpUnreach
- cmp ch,1
- ja IpIcmpRet2
- IpIcmpUnreach: ; codes 0 - 1, 6 - 12 go here
- PushfDI
- push si
- mov cl,[si].uIcmpIpHdr.iIpTos
- xor ch,ch
- mov si,cx
- call RouteFind ; this host in route table?
- pop si
- jnz IpIcmpUnfound
-
- mov ah,byte ptr [si].uIcmpTypeCode+1 ; icmp code
- xor al,al ;*test
- inc ah ; ensure non zero error code
- mov RouteTabUnreach[di],ax ; mark it unreachable
-
- call CurrentTicks ; get current ticks value
- mov RouteTabTrRx[di],cx ; set timer
- IpIcmpUnfound:
- PopfEI
- IpIcmpRet2:
- jmp IpIcmpRet
-
- IpNotUnreach:
- if RFCC
- cmp cl,4 ; source quench
- jne IpIcmpNotQuench
-
- PushfDI
- push si
- mov cl,[si].uIcmpIpHdr.iIpTos
- xor ch,ch
- mov si,cx
- call RouteFind ; this host in route table?
- pop si
- jnz IpIcmpNotRoute
-
- mov dx,RouteTabFlags[di]
- or RouteTabFlags[di],SQ_UPDATED
- lea si,RouteTabTrSq[di]
- lea di,RouteTabSqDelay[di]
- jmp short IpIcmpSq
- IpIcmpNotRoute:
- call ArpFindIp
- jnz IpIcmpSqEnd
-
- mov dx,ArpTabFlags[di]
- or ArpTabFlags[di],SQ_UPDATED
- lea si,ArpTabTrSq[di]
- lea di,ArpTabSqDelay[di]
- IpIcmpSq:
- mov ax,[di] ; get current sq delay
- or ax,ax
- jnz IpIcmpAddDelay
- call CurrentTicks
- mov [si],cx ; initialize sq timer
- mov ax,150*64/55 ; initial sq delay 178 ms
- IpIcmpAddDelay:
- add ax,28*64/55 ; increase delay by 28 ms
- test dx,SQ_UPDATED ; unless already done in
- jnz IpIcmpSqEnd ; the last two seconds
- mov [di],ax
- IpIcmpSqEnd:
- PopfEI
- jmp short IpIcmpRet
-
- IpIcmpNotQuench:
- endif ; RFCC
- cmp cl,5 ; redirect
- jne IpNotRedirect
-
- PushfDI
- push si
- mov cl,[si].uIcmpIpHdr.iIpTos
- xor ch,ch
- mov si,cx
- call RouteFind ; this host in route table?
- pop si
- jnz IpIcmpDisfound
-
- mov dx,RouteTabIpG1[di] ; icmp from the gwy used?
- mov ax,RouteTabIpG2[di]
- mov cx,di
- mov di,[bx].dPtrIp
- cmp dx,[di].iIpSrc
- jne IpIcmpDisfound
- cmp ax,[di].iIpSrc+2
- jne IpIcmpDisfound
- mov di,cx
-
- mov dx,[si].uIcmpData ; new gateway IP #
- mov ax,[si].uIcmpData+2
-
- call MyNetChk ; is he on my net?
- jnz IpIcmpDisfound
-
- mov RouteTabIpG1[di],dx ; put it into route table
- mov RouteTabIpG2[di],ax
- IpIcmpDisfound:
- PopfEI
- jmp short IpIcmpRet
-
- IpNotRedirect:
- IpIcmpRet:
- jmp IpRecRet
-
-
- ;************************************************************************
- ;* MakeMynet
- ;************************************************************************
-
- MakeMynet proc near
- mov dx,MyIpNr
- mov ax,MyIpNr+2
-
- mov ArpTabIp1+4,dx ; third arp slot = me
- mov ArpTabIp2+4,ax
- mov si,offset MyHwAd
- call ArpPutNew
-
- mov si,MyMask
- mov di,MyMask+2
- and dx,si ; calculate network #
- and ax,di
- mov MyNet,dx
- mov MyNet+2,ax
-
- not si ; second arp slot =
- not di ; subnet broadcast
- or dx,si
- or ax,di
- mov ArpTabIp1+2,dx
- mov ArpTabIp2+2,ax
- ret
- MakeMynet endp
-
-
-
- ;************************************************************************
- ;* ValidateIpNr
- ;************************************************************************
-
- ValidateIpNr proc near
- call BufAlloc
-
- mov [bx].dTimOutMsg,0 ; we SHOULD get no answer
- mov [bx].dTickTimeout,10 ; give them half a second
- mov dx,MyIpNr
- mov ax,MyIpNr+2
- call SendArpReq ; send arp to our Ip #
- call BufRelease
- jz ValConflict ; someone else has our IP # ?
-
- ret ; - no, return
-
- ValConflict: ; - yes, error termination
- call ArpFindIp
- mov cl,3
- shl di,cl
- lea si,ArpTabHwAdr[di] ; get HW addr of arp reply
-
- mov di,offset OccupiedHw
- call PutHwNum ; put offending HW addr
-
- mov dx,offset OccupiedMsg ; display IP occupied msg
- mov ah,9
- int 21h
-
- mov al,09 ; error code 9
- call terminate
- ValidateIpNr endp
-
-
-
- ;************************************************************************
- ;* DoBootpPkt
- ;************************************************************************
-
- DoBootpPkt proc near
- call CurrentTicks ; get current ticks value
- mov IpDesBuf.fBotStruc.uBotXid,cx ; as transaction id
- if RFCC
- add cx,2*18 ; initialize ageing
- mov AgeNext,cx
- mov AgeFragsNext,cx
- endif ; RFCC
- mov al,byte ptr ArpBuf.iArpHtype+1
- mov IpDesBuf.fBotStruc.uBotHtype,al ; put my HW type
-
- mov si,offset MyHwAd
- mov di,offset IpDesBuf.fBotStruc.uBotCliHwAd
- push cs
- pop es
- mov cx,Hlen
- mov IpDesBuf.fBotStruc.uBotHlen,cl
- rep movsb ; copy my HW addr
-
- mov bx,offset IpDesBuf ; frame to send
- call MakeSendDescr
- mov [bx].dWaitEvent,GOT_BOOTP ; event to wait for
- mov [bx].dTimOutMsg,offset NoBotReplyMsg ; error msg
- mov ax,BpDataLen+UDPHDRLEN ; bootp pkt length
- call SendUdpPkt ; send bootp request
-
- ret
- DoBootpPkt endp
-
-
-
- ;************************************************************************
- ;* InterpBootp according to RFC 1084 and RFC1048
- ;************************************************************************
-
- InterpBootp proc near
- mov bx,AdrBootpReply
- mov di,[bx].dPtrUdp
- mov dx,[di].uBotYourIp ; mov my IP #
- mov MyIpNr,dx ; to IP buf
- mov ax,[di].uBotYourIp+2
- mov MyIpNr+2,ax
-
- or Flagword,HAVE_MYIPNR ; note what we've got
-
- cmp word ptr [di].uBotMagNum,8263h ; RFC 1084 type of
- jne VendEnd ; vendor area?
- cmp word ptr [di].uBotMagNum+2,6353h
- jne VendEnd
-
- lea si,[di].uBotVend ; start of "vendor area"
- lea bp,[si]+64-4 ; end of "vendor area"
- push cs
- pop es
- VendLoop:
- cmp si,bp ; beyond vendor area?
- jb VendNext
-
- VendEnd:
- call BufRelease ; release bootp reply buf
- ret
-
- VendNext:
- lodsb ; get field type:
-
- cmp al,0 ; filler
- je VendLoop
-
- cmp al,1 ; netmask
- jne NotMask
- mov di,offset MyMask
- call Xtract4Bytes
- jmp short VendLoop
- NotMask:
- cmp al,2 ; zone/time (?) offset
- jne NotTimeOffs
- test Flagword,HAVE_TIMEOFFSET
- jnz VendDefault
- mov di,offset tzoffset
- call Xtract4Bytes
- or Flagword,HAVE_TIMEOFFSET
- jmp short VendLoop
- NotTimeOffs:
- cmp al,3 ; default gateways
- jne NotDefGwys
- mov di,offset DefGwys
- mov cx,MAXDEFGWYS
- mov ax,DefGwyNum
- call XtractIpNums
- add DefGwyNum,cx
- jmp short VendLoop
- NotDefGwys:
- cmp al,4 ; time servers
- jne NotTimeserv
- or Flagword,HAVE_TIMESERVER
- mov di,offset TimeServIpNr
- mov cx,MAXTSERVS
- mov ax,TservNum
- call XtractIpNums
- add TservNum,cx
- jmp short VendLoop
- NotTimeserv:
- if TBLBUILD or PINGCLIENT
- cmp al,6 ; default nameservers
- jne NotDefNS
- mov di,offset DefNS
- mov cx,MAXDEFNS
- mov ax,DefNSnum
- call XtractIpNums
- add DefNSnum,cx
- jmp short VendLoop
- NotDefNS:
- endif ; TBLBUILD or PINGCLIENT
- cmp al,0ffh ; end
- je VendEnd
- VendDefault: ; everything else
- lodsb
- xor ah,ah
- add si,ax ; skip field
- jmp Vendloop
-
- InterpBootp endp
-
-
-
- ;************************************************************************
- ;* XtractIpNums
- ;************************************************************************
-
- XtractIpNums proc near
- sub cx,ax ; wanted - already got
-
- shl ax,1
- shl ax,1
- add di,ax ; append to what we got
- shl cx,1
- shl cx,1
- jmp short XtractNBytes
- Xtract4Bytes:
- mov cl,4
- XtractNBytes:
- lodsb
- cmp cl,al ; as many as we want?
- jbe XtractOkLen
-
- mov cl,al ; - no, take what there is
- XtractOkLen:
- xor ch,ch
- xor ah,ah
- push cx
- push ax
- push si
- rep movsb ; copy field
- pop si
-
- pop ax
- add si,ax ; advance field ptr
-
- pop cx
- shr cx,1
- shr cx,1 ; cx = IP #'s read
-
- ret
- XtractIpNums endp
-
- ;========================================================================
- ; endinclude
-